from aioetcd3.client import Client
from aioetcd3.help import range_prefix
from config.config import etcd_host, etcd_port
import json
import logging
from datetime import datetime

logging.basicConfig(level=logging.INFO)

ETCD_ADDRESS = f"{etcd_host}:{etcd_port}"

def get_user_path(user_id: str, key: str = "") -> str:
    path = f"/telegram/{user_id}/{key}"
    logging.info(f"User path: {path}")
    return path

def get_stock_path(stock_name: str, key: str = "") -> str:
    path = f"/stocks/{stock_name}/{key}"
    logging.info(f"Stock path: {path}")
    return path

async def subscribe(user_id, company):
    etcd = Client(endpoint=ETCD_ADDRESS)
    try:
        user_path = get_user_path(user_id, "stock")
        stock, meta = await etcd.get(user_path)
        if stock is not None:
            stock = json.loads(stock)
            if company not in stock:
                stock.append(company)
                await etcd.put(user_path, json.dumps(stock))
            else:
                return False
        else:
            stock = [company]
            await etcd.put(user_path, json.dumps(stock))
        return True
    finally:
        await etcd.close()

async def get_info_stock(company):
    etcd = Client(endpoint=ETCD_ADDRESS)
    try:
        stock_path = get_stock_path(company)
        logging.info(f"Getting stock info from path: {stock_path}")
        value, meta = await etcd.get(stock_path)
        logging.info(f"Retrieved value: {value} from {stock_path}")
        return value if value is not None and value.strip() else ""
    finally:
        await etcd.close()

async def unsubscribe(user_id, company):
    etcd = Client(endpoint=ETCD_ADDRESS)
    try:
        user_path = get_user_path(user_id, "stock")
        stock, meta = await etcd.get(user_path)
        if stock is not None:
            stock = json.loads(stock)
            if company in stock:
                stock.remove(company)
                await etcd.put(user_path, json.dumps(stock))
                return True
        return False
    finally:
        await etcd.close()

async def check_stock(user_id):
    etcd = Client(endpoint=ETCD_ADDRESS)
    try:
        user_path = get_user_path(user_id, "stock")
        stock, meta = await etcd.get(user_path)
        if stock is not None:
            stock = json.loads(stock)
            return bool(stock)
        return False
    finally:
        await etcd.close()

async def get_stock(user_id):
    etcd = Client(endpoint=ETCD_ADDRESS)
    try:
        user_path = get_user_path(user_id, "stock")
        stock, meta = await etcd.get(user_path)
        if stock is not None:
            stock = json.loads(stock)
            return stock if stock else None
        return None
    finally:
        await etcd.close()

async def stock_exists(stock_name):
    etcd = Client(endpoint=ETCD_ADDRESS)
    try:
        stock_path = get_stock_path(stock_name)
        logging.info(f"Checking if stock exists at path: {stock_path}")
        value, meta = await etcd.get(stock_path)
        logging.info(f"Existence check value: {value}")
        return value is not None
    finally:
        await etcd.close()

async def get_latest_pointer(stock_name):
    etcd = Client(endpoint=ETCD_ADDRESS)
    try:
        pointer_path = get_stock_path(stock_name, "news/latest")
        logging.info(f"Getting latest pointer from path: {pointer_path}")
        value, meta = await etcd.get(pointer_path)
        logging.info(f"Retrieved pointer value: {value}")
        return value.decode('utf-8') if isinstance(value, bytes) else value
    finally:
        await etcd.close()

async def get_feed_by_pointer(pointer):
    etcd = Client(endpoint=ETCD_ADDRESS)
    try:
        logging.info(f"Getting feed by pointer from path: {pointer}")
        value, meta = await etcd.get(pointer)
        return value.decode('utf-8') if isinstance(value, bytes) else value
    finally:
        await etcd.close()


async def get_keys_by_prefix(prefix):
    etcd = Client(endpoint=ETCD_ADDRESS)
    try:
        keys = []
        range_end = prefix[:-1] + chr(ord(prefix[-1]) + 1)
        response = await etcd.get(prefix, range_end=range_end)
        for kv in response.kvs:
            keys.append(kv.key.decode('utf-8'))
        return keys
    finally:
        await etcd.close()


async def get_users_subscribed_to_stock(stock_name):
    etcd = Client(endpoint=ETCD_ADDRESS)
    try:
        users_subscribed = []
        user_prefix = "/telegram/"
        logging.info(f"Fetching users with prefix: {user_prefix}")
        response = await etcd.range(range_prefix(user_prefix))
        logging.info(f"Response from etcd: {response}")

        for kv in response:
            user_id = kv[0].decode('utf-8').split('/')[2]
            logging.info(f"Checking user: {user_id}")
            stock_list = json.loads(kv[1].decode('utf-8'))
            logging.info(f"Stock list for user {user_id}: {stock_list}")
            if stock_name in stock_list:
                users_subscribed.append(user_id)
        return users_subscribed
    finally:
        await etcd.close()

def format_response(feed_analytic, summary, label, link):
    # Convert timestamp to human-readable format
    timestamp = datetime.fromtimestamp(int(feed_analytic)).strftime('%Y-%m-%d %H:%M:%S')

    # Map label to smiley
    label_to_smile = {
        'positive': '😊',
        'negative': '😟',
        'neutral': '😐'
    }
    smiley = label_to_smile.get(label.lower(), '😐')

    return (f"Найдена свежая новость от {timestamp}\n"
            f"Влияние на акцию - {label} {smiley}\n"
            f"Ссылка - {link}\n\n"
            f"Краткое содержание:\n{summary}")
